/*
 * Copyright 2021 NXP
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#ifndef _FSL_PCM186X_H_
#define _FSL_PCM186X_H_

#include "fsl_codec_i2c.h"
#include "fsl_common.h"

/*!
 * @addtogroup pcm186X
 * @ingroup codec
 * @{
 */

/*******************************************************************************
 * Definitions
 ******************************************************************************/
/*! @name Driver version */
/*! @{ */
/*! @brief PCM186X driver version 2.0.1 */
#define FSL_PCM186X_DRIVER_VERSION (MAKE_VERSION(2, 0, 1))
/*! @} */

/*! @brief PCM186X handle size */
#ifndef PCM186X_I2C_HANDLER_SIZE
#define PCM186X_I2C_HANDLER_SIZE CODEC_I2C_MASTER_HANDLER_SIZE
#endif

/*! @brief Define the register addresses of PCM186X. */
#define PCM186X_REG_00           (0)
#define PCM186X_PCM_CFG          (11)
#define PCM186X_TDM_TX_OFFSET    (13)
#define PCM186X_GPIO1_0_CTRL     (16)
#define PCM186X_GPIO3_2_CTRL     (17)
#define PCM186X_GPIO1_0_DIR_CTRL (18)
#define PCM186X_GPIO3_2_DIR_CTRL (19)
#define PCM186X_GPIO_IN_OUT      (20)
#define PCM186X_CLK_CTRL         (32)
#define PCM186X_POWER_CTRL       (112)

/*! @brief PCM186X_PAGE */
#define PCM186X_RESET (0xfe)

/*! @brief Page 0, Register 11 */
#define PCM186X_RX_WLEN (3 << 6)
#define PCM186X_TX_WLEN (3 << 2)
#define PCM186X_FMT     (3 << 0)
#define PCM186X_WLEN_16 (3)
#define PCM186X_WLEN_24 (1)
#define PCM186X_WLEN_32 (0)
#define PCM186X_FMT_I2S (0)

/*! @brief Page 0, Register 16 */
#define PCM186X_GPIO0_FUNC (7 << 0)
#define PCM186X_GPIO1_FUNC (7 << 4)

/*! @brief Page 0, Register 17 */
#define PCM186X_GPIO2_FUNC (7 << 0)
#define PCM186X_GPIO3_FUNC (7 << 4)

/*! @brief Page 0, Register 18 */
#define PCM186X_GPIO0_DIR (7 << 0)
#define PCM186X_GPIO1_DIR (7 << 4)

/*! @brief Page 0, Register 19 */
#define PCM186X_GPIO2_DIR (7 << 0)
#define PCM186X_GPIO3_DIR (7 << 4)

/*! @brief Page 0, Register 32 */
#define PCM186X_SCK_XI_SEL1  (1 << 7)
#define PCM186X_SCK_XI_SEL0  (1 << 6)
#define PCM186X_SCK_SRC_PLL  (1 << 5)
#define PCM186X_MST_MODE     (1 << 4)
#define PCM186X_ADC_SRC_PLL  (1 << 3)
#define PCM186X_DSP2_SRC_PLL (1 << 2)
#define PCM186X_DSP1_SRC_PLL (1 << 1)
#define PCM186X_CLKDET_EN    (1 << 0)

/*! @brief Page 0, Register 112 */
#define PCM186X_PWRDN (1 << 2)

/*! @brief PCM186x I2C baudrate */
#define PCM186X_I2C_BAUDRATE (100000U)

/*! @brief audio bit width
 * @anchor _pcm186x_audio_bit_width
 */
enum
{
    kPCM186x_AudioBitWidth16bit = 16U, /*!< audio bit width 16 */
    kPCM186x_AudioBitWidth20bit = 20U, /*!< audio bit width 20 */
    kPCM186x_AudioBitWidth24bit = 24U, /*!< audio bit width 24 */
    kPCM186x_AudioBitWidth32bit = 32U, /*!< audio bit width 32 */
};

/*! @brief PCM186x audio format */
typedef struct _pcm186x_audio_format
{
    uint32_t mclk_HZ;    /*!< master clock frequency */
    uint32_t sampleRate; /*!< sample rate */
    uint32_t bitWidth;   /*!< bit width */
} pcm186x_audio_format_t;

/*! @brief Initialize structure of PCM186x */
typedef struct pcm186x_config
{
    pcm186x_audio_format_t format; /*!< Audio format */
    bool master_slave;             /*!< Master or slave. */
    uint8_t slaveAddress;          /*!< PCM186x device address */
    codec_i2c_config_t i2cConfig;  /*!< i2c configuration */
    uint8_t gpio_led;              /*!< led gpio number */
} pcm186x_config_t;

/*! @brief PCM186x codec handler
 */
typedef struct _pcm186x_handle
{
    const pcm186x_config_t *config;              /*!< PCM186x config pointer */
    uint8_t i2cHandle[PCM186X_I2C_HANDLER_SIZE]; /*!< i2c handle */
} pcm186x_handle_t;

/*******************************************************************************
 * API
 ******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif

/*!
 * @brief PCM186x initialise function.
 *
 * @param handle PCM186x handle structure.
 * @param config PCM186x configuration structure.
 */
status_t PCM186x_Init(pcm186x_handle_t *handle, const pcm186x_config_t *config);

/*!
 * @brief Deinit the PCM186x codec.
 *
 * This function close all modules in PCM186x to save power.
 *
 * @param handle PCM186x handle structure pointer.
 */
status_t PCM186x_Deinit(pcm186x_handle_t *handle);

/*!
 * @brief Configure the data format of audio data.
 *
 * This function would configure the registers about the sample rate, bit depths.
 *
 * @param handle PCM186x handle structure pointer.
 * @param sysclk system clock of the codec which can be generated by MCLK or PLL output.
 * @param sample_rate Sample rate of audio file running in PCM186x.
 * @param bits Bit depth of audio file.
 */
status_t PCM186x_SetFormat(pcm186x_handle_t *handle, uint32_t sysclk, uint32_t sample_rate, uint32_t bits);

/*!
 * @brief Write register to PCM186x using I2C.
 *
 * @param handle PCM186x handle structure.
 * @param reg The register address in PCM186x.
 * @param val Value needs to write into the register.
 */
status_t PCM186x_WriteReg(pcm186x_handle_t *handle, uint8_t reg, uint8_t val);

/*!
 * @brief Read register from PCM186x using I2C.
 * @param handle PCM186x handle structure.
 * @param reg The register address in PCM186x.
 * @param val Value written to.
 */
status_t PCM186x_ReadReg(pcm186x_handle_t *handle, uint8_t reg, uint8_t *val);

/*!
 * @brief Modify some bits in the register using I2C.
 * @param handle PCM186x handle structure.
 * @param reg The register address in PCM186x.
 * @param mask The mask code for the bits want to write. The bit you want to write should be 0.
 * @param val Value needs to write into the register.
 */
status_t PCM186x_ModifyReg(pcm186x_handle_t *handle, uint8_t reg, uint8_t mask, uint8_t val);

#if defined(__cplusplus)
}
#endif

/*! @} */

#endif /* _FSL_PCM186X_H_ */

/*******************************************************************************
 * API
 ******************************************************************************/
